﻿using mozhi.smarterp.Business.Sales.ProductPrice;
using mozhi.smarterp.Business.Sales.Repositories;
using mozhi.smarterp.Business.Sales.Services;
using Mozhi.Abp.Domain.BasicData;
using Mozhi.Abp.Domain.BasicData.Repositories;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;

namespace mozhi.smarterp.Business.Sales.ProductPrices
{
    public class SaleProductPriceAppService : BusinessAppService, ISaleProductPriceAppService
    {
        private ISaleProductPriceRepository _repository;
        private IProductRepository _productRepository;
        private ICustomerRepository _customerRepository;
        private ITaxRateRepository _taxRateRepository;
        private IUnitRepository _unitRepository;
        private SaleProductPriceManager _manager;
        private ICurrencyRepository _currencyRepository;

        public SaleProductPriceAppService(ISaleProductPriceRepository repository, IProductRepository productRepository, ICustomerRepository customerRepository, ITaxRateRepository taxRateRepository,
            IUnitRepository unitRepository, SaleProductPriceManager manager, ICurrencyRepository currencyRepository)
        {
            _repository = repository;
            _productRepository = productRepository;
            _customerRepository = customerRepository;
            _taxRateRepository = taxRateRepository;
            _unitRepository = unitRepository;
            _manager = manager;
            _currencyRepository = currencyRepository;
        }

        public async Task<SaleProductPriceDto> CreateAsync(SaleProductPriceCreateDto input)
        {
            var saleProductPrice = await _manager.GetAsync(null, input.Code, input.Name, input.CustomerId, input.CurrencyId, input.IncludeTax);

            input.Items = input.Items ?? new List<SaleProductPriceItemCreateDto>();

            var saleProductPriceItems = new List<SaleProductPriceItem>();

            foreach (var item in input.Items)
            {
                var salePriceItem = await _manager.GetItemAsync(null, item.ProductId, item.MinQuantity, item.MaxQuantity, item.Price, item.TaxRateId, item.EffectiveDate, item.ExpirationDate);

                saleProductPriceItems.Add(salePriceItem);
            }

            saleProductPrice.SetItems(saleProductPriceItems);

            saleProductPrice = await _repository.InsertAsync(saleProductPrice);

            var result = ObjectMapper.Map<SaleProductPrice, SaleProductPriceDto>(saleProductPrice);

            await LoadOtherInfoAsync(new List<SaleProductPriceDto> { result });

            return result;
        }

        public async Task DeleteAsync(Guid id)
        {
            await _repository.DeleteAsync(id);
        }

        public async Task<SaleProductPriceDto> GetAsync(Guid id)
        {
            var saleProductPrice = await _repository.GetAsync(id);

            if (saleProductPrice == null)
                return null;

            var result = ObjectMapper.Map<SaleProductPrice, SaleProductPriceDto>(saleProductPrice);

            await LoadOtherInfoAsync(new List<SaleProductPriceDto> { result });

            return result;

        }

        public async Task<PagedResultDto<SaleProductPriceDto>> GetListAsync(SaleProductPricePagedResultRequestDto filter)
        {
            var count = await _repository.GetCountAsync(filter.keyword, null, null, filter.CustomerId, filter.CurrencyId, null);

            var entities = await _repository.GetPagedListAsync(filter.keyword, null, null, filter.CustomerId, filter.CurrencyId, filter.SkipCount, filter.MaxResultCount, filter.Sorting);

            var items = ObjectMapper.Map<List<SaleProductPrice>, List<SaleProductPriceDto>>(entities);

            await LoadOtherInfoAsync(items);

            return new PagedResultDto<SaleProductPriceDto>()
            {
                Items = items,
                TotalCount = count
            };
        }

        public Task<List<SaleProductPriceItemDto>> GetListAsync(SaleProductPriceResultRequestDto filter)
        {
            throw new NotImplementedException();
        }

        public async Task<SaleProductPriceDto> UpdateAsync(SaleProductPriceUpdateDto input)
        {
            var saleProductPrice = await _manager.GetAsync(input.Id, input.Code, input.Name, input.CustomerId, input.CurrencyId, input.IncludeTax);

            input.Items = input.Items ?? new List<SaleProductPriceItemUpdateDto>();

            var saleProductPriceItems = new List<SaleProductPriceItem>();

            foreach (var item in input.Items)
            {
                var salePriceItem = await _manager.GetItemAsync(item.Id, item.ProductId, item.MinQuantity, item.MaxQuantity, item.Price, item.TaxRateId, item.EffectiveDate, item.ExpirationDate);

                saleProductPriceItems.Add(salePriceItem);
            }

            saleProductPrice.SetItems(saleProductPriceItems);

            saleProductPrice = await _repository.UpdateAsync(saleProductPrice);

            var result = ObjectMapper.Map<SaleProductPrice, SaleProductPriceDto>(saleProductPrice);

            await LoadOtherInfoAsync(new List<SaleProductPriceDto> { result });

            return result;
        }

        #region
        private async Task LoadOtherInfoAsync(List<SaleProductPriceDto> inputs)
        {
            if (inputs.IsNullOrEmpty())
                return;

            foreach (var input in inputs)
            {
                var customer = input.CustomerId.HasValue ? await _customerRepository.GetAsync(input.CustomerId.Value) : null;
                var currency = await _currencyRepository.GetAsync(input.CurrencyId);

                input.CustomerCode = customer?.Code;
                input.CusomterName = customer?.Name;
                input.CurrencyCode = currency?.Code;

                foreach (var item in input.Items)
                {
                    var product = await _productRepository.GetAsync(item.ProductId);
                    var basicUnit = await _unitRepository.GetAsync(item.BasicUnitId);
                    var taxRate = item.TaxRateId.HasValue ? await _taxRateRepository.GetAsync(item.TaxRateId.Value) : null;

                    item.ProductCode = product?.Code;
                    item.ProductName = product?.Name;
                    item.BasicUnitName = basicUnit?.Name;
                    item.TaxRateName = taxRate?.Name;
                }
            }
        }
        #endregion
    }
}
